﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Collections;
using Silvermoon.OpenGL.Native;

namespace Silvermoon.OpenGL
{
    /// <summary>
    /// Textsprite with highlight functionality for each individual character.
    /// </summary>
    public class HighlightTextSprite : TextSprite
    {
        private Color highlightColor = Color.Yellow;
        private BitArray highlightedChars;
        private int highlightCount = 0;
        private VectorQuads[] highlightedRects;

        public Color HighlightColor
        {
            get { return highlightColor; }
            set
            {
                if (highlightColor != value)
                {
                    highlightColor = value;
                    Invalidate();
                }
            }
        }

        public bool IsHighlighted { get { return highlightedChars != null; } }

        protected override void OnTextChanged()
        {
            if (highlightedChars != null)
            {
                highlightedChars = null;
                Invalidate();
            }
            base.OnTextChanged();
        }

        protected override void LayoutCharacters()
        {
            base.LayoutCharacters();
            AddHighlightRects();
        }

        private void AddHighlightRects()
        {
            if (IsHighlighted)
            {
                int n = highlightedChars.Length;
                if (highlightedRects == null || highlightedRects.Length < n) highlightedRects = new VectorQuads[n + 4];
                int index = 0;
                int charSpace = CharSpace;
                for (int i = 0; i < n; i++)
                {
                    if (highlightedChars[i])
                    {
                        highlightedRects[index] = vertexMap[i];
                        if (charSpace != 0) highlightedRects[index].AdWidth(charSpace);
                        index++;
                    }
                }
                highlightCount = index;
            }
        }

        public void ClearHighlights()
        {
            if (highlightedChars != null)
            {
                highlightCount = 0;
                highlightedRects = null;
                highlightedChars = null;
                Invalidate();
            }
        }

        public void Highlight(int index)
        {
            if (index < 0 || index >= Length) throw new ArgumentOutOfRangeException("index");
            if (highlightedChars == null) highlightedChars = new BitArray(Length);
            highlightedChars.Set(index, true);
            Invalidate();
        }

        public void Highlight(params int[] indexes)
        {
            if (highlightedChars == null) highlightedChars = new BitArray(VisibleCharacters);
            foreach (var index in indexes)
            {
                if (index < 0 || index >= VisibleCharacters) throw new ArgumentOutOfRangeException("index");
                highlightedChars.Set(index, true);
            }
            Invalidate();
        }

        public void HighlightRange(int from, int to)
        {
            if (from < 0 || from >= Length) throw new ArgumentOutOfRangeException("from");
            if (to > Length) to = Length;
            if (to < 0 || to > Length) throw new ArgumentOutOfRangeException("to");
            if (highlightedChars == null) highlightedChars = new BitArray(Length);
            for (int i = from; i < to; i++)
            {
                highlightedChars.Set(i, true);
            }
            Invalidate();
        }

        protected override void PreRender(int offset, int len)
        {
            if (IsHighlighted)
            {
                Color color = highlightColor;
                gl.Color4x(color.R << 8, color.G << 8, color.B << 8, color.A << 8);
                gl.CheckError();

                gl.Disable(Capability.Texture2D);
                SetVertex();
                gl.DrawElements(PrimitiveType.Triangles, 6 * highlightCount, glValueType.UnsignedShort, indexes);
                gl.CheckError();

                gl.Enable(Capability.Texture2D);
            }
        }

        private unsafe void SetVertex()
        {
            fixed (void* v = &highlightedRects[0])
            {
                gl.VertexPointer(2, glValueType.Short, 0, v);
            }
        }
    }
}
